﻿#include"XQTaskGroup.h"
#include"XQTaskPool.h"
#include"XQFuncEventFilter.hpp"
#include"XQFuncEvent.h"
#include"XQRunnable.h"
#include<QCoreApplication>
#include<QDebug>
XQTaskGroup::XQTaskGroup(QObject* parent)
	:QObject(parent)
{
	init();
}

XQTaskGroup::~XQTaskGroup()
{
	requestInterruption();
	wait();
}
size_t XQTaskGroup::size()
{
	QReadLocker lock(&m_poolLock);
	return m_poolMap.size();
}

XQTaskPool* XQTaskGroup::taskPool(const QString& name)
{
	QReadLocker lock(&m_poolLock);
	auto it=m_poolMap.find(name);
	if (it == m_poolMap.end())
		return nullptr;
	return it->second;
}

XQTaskPool* XQTaskGroup::addTaskPool(const QString& name)
{
	QWriteLocker lock(&m_poolLock);
	auto it = m_poolMap.find(name);
	if(it == m_poolMap.end())
	{
		auto pool = new XQTaskPool(this);
		m_poolMap[name]=pool;
		init_taskPool(pool);
		pool->setName(name);
		return pool;
	}
	return it->second;
}

void XQTaskGroup::freeTaskPool(const QString& name)
{
	QWriteLocker lock(&m_poolLock);
	auto it = m_poolMap.find(name);
	if (it != m_poolMap.end())
	{
		m_poolMap.erase(it);
		disconnect_taskPool(it->second);
		it->second->deleteLater();
	}
}

void XQTaskGroup::removeTaskPool(const QString& name)
{
	QWriteLocker lock(&m_poolLock);
	auto it = m_poolMap.find(name);
	if (it != m_poolMap.end())
	{
		m_poolMap.erase(it);
		disconnect_taskPool(it->second);
	}
}

void XQTaskGroup::requestInterruption()
{
	QReadLocker lock(&m_poolLock);
	for (auto& pool: m_poolMap)
	{
		pool.second->requestInterruption();
	}
}

void XQTaskGroup::requestInterruption(const QString& name)
{
	QReadLocker lock(&m_poolLock);
	auto taskPool = m_poolMap.find(name);
	if (taskPool != m_poolMap.end())
		(taskPool->second)->requestInterruption();
}

void XQTaskGroup::wait()
{
	QReadLocker lock(&m_poolLock);
	for (auto&pool: m_poolMap)
	{
		pool.second->wait();
	}
}

void XQTaskGroup::wait(const QString& name)
{
	while (true)
	{
		auto pool = taskPool(name);
		if (pool)
			pool->wait();
		else
			break;
	}
}

void XQTaskGroup::wait(const QString& name, XQRunnable* task)
{
	while (true)
	{
		auto pool = taskPool(name);
		if (pool)
			pool->wait(task);
		else
			break;
	}
}

void XQTaskGroup::wait_event()
{
	QReadLocker lock(&m_poolLock);
	for (auto& pool : m_poolMap)
	{
		pool.second->wait_event();
	}
}

void XQTaskGroup::wait_event(const QString& name)
{
	QReadLocker lock(&m_poolLock);
	auto taskPool = m_poolMap.find(name);
	if (taskPool != m_poolMap.end())
		(taskPool->second)->wait_event();
}

void XQTaskGroup::wait_event(const QString& name, XQRunnable* task)
{
	QReadLocker lock(&m_poolLock);
	auto taskPool = m_poolMap.find(name);
	if (taskPool != m_poolMap.end())
		(taskPool->second)->wait_event(task);
}

void XQTaskGroup::init()
{
	installEventFilter(new XQFuncEventFilter(this));
	connect(qApp, &QCoreApplication::aboutToQuit, this, [=] {
		requestInterruption();
		wait();
		});
}

void XQTaskGroup::init_taskPool(XQTaskPool* pool)
{
	if (pool == nullptr)
		return;
	connect(pool, QOverload<XQTaskPool*>::of(&XQTaskPool::start), this, QOverload<XQTaskPool*>::of(&XQTaskGroup::taskPoolStart));
	connect(pool, QOverload<const QString&>::of(&XQTaskPool::start), this, QOverload<const QString&>::of(&XQTaskGroup::taskPoolStart));
	connect(pool, QOverload<XQTaskPool*>::of(&XQTaskPool::finish), this, QOverload<XQTaskPool*>::of(&XQTaskGroup::taskPoolFinish));
	connect(pool, QOverload<const QString&>::of(&XQTaskPool::finish), this, QOverload<const QString&>::of(&XQTaskGroup::taskPoolFinish));
	connect(pool, QOverload<XQRunnable*>::of(&XQTaskPool::taskStart), this, QOverload<XQRunnable*>::of(&XQTaskGroup::taskStart));
	connect(pool, QOverload<XQRunnable*>::of(&XQTaskPool::taskFinish), this, QOverload<XQRunnable*>::of(&XQTaskGroup::taskFinish));
}

void XQTaskGroup::disconnect_taskPool(XQTaskPool* pool)
{
	if (pool == nullptr)
		return;
	disconnect(pool, QOverload<XQTaskPool*>::of(&XQTaskPool::start), this, QOverload<XQTaskPool*>::of(&XQTaskGroup::taskPoolStart));
	disconnect(pool, QOverload<const QString&>::of(&XQTaskPool::start), this, QOverload<const QString&>::of(&XQTaskGroup::taskPoolStart));
	disconnect(pool, QOverload<XQTaskPool*>::of(&XQTaskPool::finish), this, QOverload<XQTaskPool*>::of(&XQTaskGroup::taskPoolFinish));
	disconnect(pool, QOverload<const QString&>::of(&XQTaskPool::finish), this, QOverload<const QString&>::of(&XQTaskGroup::taskPoolFinish));
	disconnect(pool, QOverload<XQRunnable*>::of(&XQTaskPool::taskStart), this, QOverload<XQRunnable*>::of(&XQTaskGroup::taskStart));
	disconnect(pool, QOverload<XQRunnable*>::of(&XQTaskPool::taskFinish), this, QOverload<XQRunnable*>::of(&XQTaskGroup::taskFinish));
}

